package it.java.giw.solr;

import it.java.giw.jsf.DocResult;
import it.java.giw.jsf.Result;

import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.SpellCheckResponse;
import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.params.ModifiableSolrParams;

/**
 * PRIMA DI MODIFICARE FARE UNA COPIA DI BACKUP O NON PUSHARE SOPRA
 * TODO:
 * - integrare i facet nel result, facet query
 * - indicizzare IMMAGINI da mettere nel cubo
 */
public class Searcher implements Serializable{
	private String collatedQuery;
	private String originalQuery;
	private static final long serialVersionUID = -4629314027623692321L;

	public Result search(String queryStrings) throws MalformedURLException, SolrServerException {
		this.originalQuery = queryStrings;
		QueryResponse response = null;
		if (queryStrings != null &&  !queryStrings.isEmpty()) { 

			try {
				SolrServer server = new HttpSolrServer("http://localhost:8983/solr");
				ModifiableSolrParams params = new ModifiableSolrParams();
				params.set("qt", "/browse");
				params.set("spellcheck", "true");
				params.set("spellcheck.collate", "true");
//				System.out.println(params);
				SolrQuery query = new SolrQuery();
				query.setQuery(queryStrings);
				query.add(params);
				
				response = server.query(query);
				response = getSuggestions(queryStrings, server, response);			
			}
			catch(Exception e){
				e.printStackTrace();
			}	
		}	
		/* create Result {originalQuery, collated, List<DocResult>, Map<String, Integer> facet2frequency} */
		return createResult(response);
	}
	
	
	public Result searchWithoutSuggestions(String queryStrings) throws MalformedURLException, SolrServerException {
		this.originalQuery = queryStrings;
		QueryResponse response = null;
		if (queryStrings != null &&  !queryStrings.isEmpty()) { 

			try {
				SolrServer server = new HttpSolrServer("http://localhost:8983/solr");
				SolrQuery query = new SolrQuery();
				ModifiableSolrParams params = new ModifiableSolrParams();
				params.set("qt", "/browse");				
				params.set("facet", "true");
				query.setHighlight(true);
				query.setHighlightSnippets(3);
				/* highlight calcolato sul campo description */
				query.addHighlightField("description");
				query.addHighlightField("content");
				query.add(params);
				query.setQuery(queryStrings);
				query.add(params);
				response = server.query(query);
			}
			catch(Exception e){
				e.printStackTrace();
			}	
		}	
		/* create Result {originalQuery, collated, List<DocResult>, Map<String, Integer> facet2frequency} */
		return createResult(response);
	}


	private Result createResult(QueryResponse response) {
		Result r = new Result();
		r.setCollatedQuery(this.collatedQuery);
		r.setOriginalQuery(this.originalQuery);
		List<DocResult> docResults = new ArrayList<DocResult>();
		for (SolrDocument d : response.getResults()){
			DocResult doc = new DocResult();
			doc.setTitle(d.getFieldValue("title").toString());
			doc.setId(d.getFieldValue("id").toString());
			doc.setSnippet(getSnippet(doc.getId(), response));
			
			docResults.add(doc);
		}
		r.setDocs(docResults);
		Map<String, Integer> facet2occurrency = response.getFacetQuery();
		facet2occurrency = filter(facet2occurrency);
		r.setFacet2frequency(facet2occurrency);
		return r;
	}

	
	private Map<String, Integer> filter(Map<String, Integer> facet2occurrency) {
		Map<String, Integer> newMap = new HashMap<String, Integer>();
		String f_max;
		int o_max;
		/* ricerca delle prime 54 facet query per num di occorrenze */
		for (int i = 0; i<54; i++){
			f_max = "";
			o_max = -1;
			/* cerco la stringa con il numero più alto di occorrenze */
			for (String facet : facet2occurrency.keySet()){
				if (facet2occurrency.get(facet) > o_max){
					f_max = facet;
					o_max = facet2occurrency.get(facet);
				}
			}
			/* la cancello dalla mappa originale e la inserisco in quella filtrata */
			facet2occurrency.remove(f_max);
			newMap.put(f_max, o_max);
		}
		return newMap;
	}


	
	private String getSnippet(String docID, QueryResponse r){
		String snippet = "";
		Map<String, Map<String, List<String>>> doc2Fiel2snippet = r.getHighlighting();
		Map<String, List<String>> field2snippet = doc2Fiel2snippet.get(docID);
		for(String field : field2snippet.keySet()){
			for(String fieldSnippet : field2snippet.get(field)){
				snippet += "...";
				snippet+= fieldSnippet;
			}
			snippet+="...";
		}
		return snippet;
		
	}
	
	private QueryResponse getSuggestions(String queryStrings, SolrServer server, QueryResponse response)
			throws SolrServerException {
		boolean found;
		SpellCheckResponse scr = null;
		String collatedString ="";
		if(response != null){
			scr = response.getSpellCheckResponse();
			if(scr != null){
				List<Suggestion> suggLst = scr.getSuggestions();
				queryStrings = queryStrings.toLowerCase();
				StringTokenizer tokenizer = new StringTokenizer(queryStrings);
				while (tokenizer.hasMoreTokens()){
					found = false;
					String token = tokenizer.nextToken();
					if (suggLst.isEmpty())
						collatedString = queryStrings;
					else{
						for (Suggestion sugg : suggLst){
							if (token.equals(sugg.getToken())){
								collatedString = collatedString.concat(sugg.getAlternatives().get(0)+" ");
								found = true;
								break;
							}
						}
						if (!found)
							collatedString = collatedString.concat(token+" ");
					}
				}
			}
		}
		
		/* response ricalcolata sulla stringa collated, con boosting per phrase query */
		SolrQuery queryCollated = new SolrQuery(collatedString+boost(collatedString));
		ModifiableSolrParams params = new ModifiableSolrParams();
		params.set("qt", "/browse");
		params.set("facet", "true");
		queryCollated.setHighlight(true);
		queryCollated.setHighlightSnippets(3);
		/* highlight calcolato sul campo description */
		queryCollated.addHighlightField("description");
		queryCollated.addHighlightField("content");
		queryCollated.add(params);
		response = server.query(queryCollated);
		/* set collated query */
		this.setCollatedQuery(collatedString);
		return response;
	}

	private void setCollatedQuery(String collatedString) {
		this.collatedQuery = collatedString;
	}

	private String boost(String collated) {
		String boostedPhraseQuery = " OR \""+collated+"\"^150";
		return boostedPhraseQuery;
	}
}